package org.springframework.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.framework.AdvisorChainFactory;
import org.springframework.aop.framework.DefaultAdvisorChainFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Name AdvisedSupport
 * @Description: 代理通知 [配置] 支持类
 * 描述信息：代理通知 [配置] 支持类, 用于聚合目标对象、目标方法拦截器、目标方法匹配器等代理组件，然后提供给代理实现类。
 * - 目标方法匹配器：用于匹配符合切点表达式过滤规则的目标方法。
 * - 目标方法拦截器：拦截匹配到的目标方法，在其执行前后增加代理行为。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-03-27 15:19:01
 **/
public class AdvisedSupport {
    // 目标代理底层实现原理：true [CGLIB]，false [JDK]
    private boolean proxyTargetClass = false;
    // 目标对象
    private TargetSource targetSource;
    // 目标方法匹配器
    private MethodMatcher methodMatcher;
    // 拦截器链工厂
    AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
    // 目标方法拦截器链
    private List<Advisor> advisors = new ArrayList<>();
    // 目标方法拦截器链缓存（线程安全）：如果该方法已经获取过拦截器，则直接取缓存，否则通过 AdvisorChainFactory 获取拦截器链。
    private transient Map<Integer, List<Object>> methodCache;

    public AdvisedSupport() {
        this.methodCache = new ConcurrentHashMap<>();
    }

    public boolean isProxyTargetClass() {
        return proxyTargetClass;
    }

    public void setProxyTargetClass(boolean proxyTargetClass) {
        this.proxyTargetClass = proxyTargetClass;
    }

    public List<Advisor> getAdvisors() {
        return advisors;
    }

    public void addAdvisor(Advisor advisor) {
        advisors.add(advisor);
    }

    public TargetSource getTargetSource() {
        return targetSource;
    }

    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = targetSource;
    }

    public MethodMatcher getMethodMatcher() {
        return methodMatcher;
    }

    public void setMethodMatcher(MethodMatcher methodMatcher) {
        this.methodMatcher = methodMatcher;
    }

    /**
     * 获取目标方法的拦截器链及动态拦截通知
     *
     * @param method      目标方法
     * @param targetClass 目标类
     * @return java.util.List<java.lang.Object> 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-12 18:07:17
     */
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
        Integer cacheKey = method.hashCode();
        List<Object> cached = methodCache.get(cacheKey);
        if (cached == null) {
            cached = advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
            methodCache.put(cacheKey, cached);
        }
        return cached;
    }

}

